# -*- coding: utf-8 -*-
"""
PyScreenBrain 后端架构验证脚本 (增强版)

此脚本用于验证 Refactor 后的 AgentService 是否能正常工作。
流程：用户输入 -> API -> AgentService -> LLM -> MCP工具 -> LLM -> 返回结果
新增功能：实时显示MCP工具调用过程
"""

import os
import sys
import json
import time
import logging
from flask import Flask, request, jsonify, render_template_string
from flask_cors import CORS

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 添加项目路径到系统路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# ==================== 核心依赖引入 ====================
from app.extensions import db
from app.services.agent_service import AgentService  # [关键] 引入核心服务
from app.api.v1.chat.services import save_user_message, save_ai_response, get_conversation_history
from app.models.user import User
from app.models.conversation import Conversation
from app.config import Config
from flask_migrate import Migrate



# ==================== 工具调用过程追踪 ====================

# 全局变量用于存储工具调用过程
tool_execution_logs = {}

# 预定义常见工具的描述模板
tool_descriptions = {
    'browser_navigate': ('打开网页', lambda params: f'导航到 {params.get("url", "未知页面")}'),
    'browser_click': ('点击元素', lambda params: f'点击页面上的 "{params.get("element", "未知元素")}"'),
    'browser_type': ('输入文本', lambda params: f'在 "{params.get("element", "未知输入框")}" 中输入文本'),
    'browser_wait_for': ('等待页面加载', lambda params: f'等待页面上的 "{params.get("text", "特定内容")}" 出现'),
    'browser_get_text': ('获取文本内容', lambda params: f'获取 "{params.get("element", "页面元素")}" 的文本内容'),
    'browser_get_screenshot': ('截取页面截图', lambda params: '捕获当前页面的截图'),
    'browser_snapshot': ('页面快照', lambda params: '获取页面当前状态快照'),
    'browser_press_key': ('按键操作', lambda params: f'按下 {params.get("key", "未知按键")} 键'),
    'browser_select_option': ('选择选项', lambda params: f'在下拉框中选择选项'),
    'browser_hover': ('悬停元素', lambda params: f'悬停在 "{params.get("element", "未知元素")}" 上'),
    'finish_task': ('完成任务', lambda params: f'任务完成: {params.get("reason", "未知原因")}')
}

def get_tool_description(tool_name, params):
    """获取工具调用的友好描述"""
    if tool_name in tool_descriptions:
        action_name, description_func = tool_descriptions[tool_name]
        return f"🔧 {action_name}: {description_func(params)}"
    else:
        return f"🔧 调用工具: {tool_name}"

def add_tool_log(conversation_id, step, tool_name, params, status="执行中", result=None):
    """添加工具调用日志"""
    if conversation_id not in tool_execution_logs:
        tool_execution_logs[conversation_id] = []
    
    log_entry = {
        'step': step,
        'tool_name': tool_name,
        'description': get_tool_description(tool_name, params),
        'params': params,
        'status': status,
        'result': result,
        'timestamp': time.time()
    }
    
    tool_execution_logs[conversation_id].append(log_entry)
    
    # 打印到控制台
    print(f"📝 [工具调用] {log_entry['description']} - {status}")
    
    return log_entry

# 创建 Flask 应用
app = Flask(__name__)
# 使用测试数据库，避免污染生产数据
# 使用配置管理数据库路径，避免硬编码
debug_db_path = Config.DEBUG_DATABASE_URL
app.config['SQLALCHEMY_DATABASE_URI'] = debug_db_path
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'debug-secret-key'
# 确保 Config 中的 MCP 地址被正确加载
app.config['MCP_SERVER_URL'] = Config.MCP_SERVER_URL

# 确保调试数据库目录存在
if debug_db_path.startswith('sqlite:///'):
    # 从SQLite路径中提取文件路径
    db_file_path = debug_db_path.replace('sqlite:///', '')
    db_dir = os.path.dirname(db_file_path)
    if db_dir and not os.path.exists(db_dir):
        os.makedirs(db_dir, exist_ok=True)

CORS(app)
db.init_app(app)


# ==================== 验证接口 ====================

@app.route('/api/debug/history', methods=['GET'])
def debug_get_history():
    """
    调试专用的历史记录接口
    直接调用 get_history_records 函数，不经过复杂的 JWT 认证，方便测试
    """
    try:
        # 获取查询参数
        limit = request.args.get('limit', 20, type=int)
        offset = request.args.get('offset', 0, type=int)
        
        # 模拟用户上下文（debug模式下使用固定用户ID）
        from flask import g
        g.user = User.query.get(1)  # 使用测试用户
        
        # 直接调用统一 HistoryService 获取历史记录
        from app.services.history_service import HistoryService
        from flask import g
        histories = HistoryService.list_histories_for_user(user_id=g.user.id, limit=limit, offset=offset)
        
        # 返回结果
        return jsonify({'histories': histories}), 200
        
    except Exception as e:
        import traceback
        traceback.print_exc()
        return jsonify({'error': str(e)}), 500

@app.route('/api/debug/chat', methods=['POST'])
def debug_chat():
    """
    调试专用的聊天接口
    直接调用 AgentService，不经过复杂的 JWT 认证，方便测试
    """
    try:
        data = request.get_json()
        user_input = data.get('message')
        conversation_id = data.get('conversation_id')

        if not user_input:
            return jsonify({'code': 400, 'msg': '请输入消息'}), 400

        # 1. 模拟/获取上下文
        if not conversation_id:
            # 如果没传ID，创建一个临时的会话记录
            conv = Conversation(title=user_input[:20], user_id=1)
            db.session.add(conv)
            db.session.commit()
            conversation_id = conv.id
            history_messages = []
        else:
            # 获取历史记录
            success, _, history_data = get_conversation_history(conversation_id)
            history_messages = history_data.get('messages', []) if success else []

        print(f"🚀 [验证] 开始处理消息: {user_input} (ConvID: {conversation_id})")

        # 2. 保存用户消息
        save_user_message(conversation_id, user_input)

        # 3. [核心] 初始化 AgentService 并调用
        agent_service = AgentService()

        # handle_user_message 内部会自动处理：
        # LLM调用 -> 识别工具 -> 调用MCP -> 拿到结果 -> 再次调用LLM -> 返回最终文本
        result = agent_service.handle_user_message(
            conversation_id=str(conversation_id),
            user_input=user_input,
            history_messages=history_messages
        )

        ai_content = result['message']['content']
        execution_id = result['message'].get('execution_id')
        tool_execution_logs = result.get('tool_execution_logs', [])

        # 4. 保存结果
        save_ai_response(conversation_id, ai_content, execution_id)

        print(f"✅ [验证] 处理完成，返回结果长度: {len(ai_content)}")
        print(f"🔧 [工具调用] 共执行了 {len(tool_execution_logs)} 个工具调用")

        return jsonify({
            'code': 200,
            'data': {
                'conversation_id': conversation_id,
                'message': ai_content,
                'execution_id': execution_id,
                'tool_execution_logs': tool_execution_logs
            },
            'msg': 'success'
        })

    except Exception as e:
        import traceback
        traceback.print_exc()
        return jsonify({'code': 500, 'msg': str(e)}), 500


@app.route('/')
def index():
    """简单的前端测试界面"""
    html_template = """
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>PyScreenBrain 核心架构验证</title>
        <style>
            body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 1400px; margin: 0 auto; padding: 20px; background-color: #f4f6f8; }
            .container { background: white; padding: 30px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
            h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; }
            .main-content { display: flex; gap: 20px; }
            .history-section { flex: 1; min-width: 250px; }
            .chat-section { flex: 2; }
            .tools-section { flex: 1; }
            .chat-box { height: 500px; overflow-y: auto; border: 1px solid #e1e4e8; border-radius: 8px; padding: 20px; margin-bottom: 20px; background: #fafafa; }
            .tools-box { height: 500px; overflow-y: auto; border: 1px solid #e1e4e8; border-radius: 8px; padding: 20px; margin-bottom: 20px; background: #fafafa; }
            .history-box { height: 500px; overflow-y: auto; border: 1px solid #e1e4e8; border-radius: 8px; padding: 10px; margin-bottom: 10px; background: #fafafa; }
            .message { margin-bottom: 15px; padding: 12px 16px; border-radius: 8px; max-width: 80%; line-height: 1.5; }
            .user { background-color: #007bff; color: white; margin-left: auto; }
            .ai { background-color: #fff; border: 1px solid #ddd; color: #333; }
            .tool-log { margin-bottom: 10px; padding: 10px; border-radius: 6px; border-left: 4px solid #007bff; background: #f8f9fa; }
            .tool-log.started { border-left-color: #ffc107; background: #fff3cd; }
            .tool-log.completed { border-left-color: #28a745; background: #d4edda; }
            .tool-log.failed { border-left-color: #dc3545; background: #f8d7da; }
            .tool-step { font-weight: bold; color: #495057; }
            .tool-name { font-weight: bold; color: #007bff; }
            .tool-status { font-size: 0.85em; padding: 2px 6px; border-radius: 3px; margin-left: 8px; }
            .tool-status.started { background: #ffc107; color: #856404; }
            .tool-status.completed { background: #28a745; color: #155724; }
            .tool-status.failed { background: #dc3545; color: #721c24; }
            .tool-args { font-size: 0.85em; color: #6c757d; margin-top: 5px; }
            .tool-result { font-size: 0.85em; color: #495057; margin-top: 5px; background: #e9ecef; padding: 5px; border-radius: 3px; }
            .input-group { display: flex; gap: 10px; }
            input[type="text"] { flex: 1; padding: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px; }
            button { background-color: #28a745; color: white; padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; font-size: 16px; }
            button:disabled { background-color: #ccc; cursor: not-allowed; }
            button:hover:not(:disabled) { background-color: #218838; }
            .refresh-btn { width: 100%; padding: 8px; font-size: 14px; background-color: #007bff; }
            .refresh-btn:hover { background-color: #0056b3; }
            img { max-width: 100%; border-radius: 4px; margin-top: 10px; border: 1px solid #eee; }
            pre { background: #f1f1f1; padding: 10px; border-radius: 4px; overflow-x: auto; }
            .loading { text-align: center; color: #666; font-size: 0.9em; margin-top: 10px; display: none;}
            .section-title { font-size: 1.2em; font-weight: bold; margin-bottom: 10px; color: #495057; }
            .history-item { margin-bottom: 10px; padding: 12px; border-radius: 6px; border: 1px solid #e1e4e8; background: white; cursor: pointer; transition: all 0.2s ease; }
            .history-item:hover { border-color: #007bff; box-shadow: 0 2px 4px rgba(0,123,255,0.1); transform: translateY(-1px); }
            .history-item.selected { border-color: #007bff; background-color: #e7f3ff; }
            .history-item .history-title { font-weight: bold; color: #2c3e50; margin-bottom: 4px; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
            .history-item .history-desc { font-size: 0.85em; color: #6c757d; margin-bottom: 6px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
            .history-item .history-meta { font-size: 0.75em; color: #999; display: flex; justify-content: space-between; align-items: center; }
            .history-item .history-status { padding: 2px 6px; border-radius: 3px; font-size: 0.7em; }
            .history-status.completed { background-color: #d4edda; color: #155724; }
            .history-status.pending { background-color: #fff3cd; color: #856404; }
            .history-status.failed { background-color: #f8d7da; color: #721c24; }
            .history-status.replay { background-color: #e2e3e5; color: #383d41; }
        </style>
        <!-- 引入 Markdown 解析库 -->
        <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1>🤖 架构验证: Agent + MCP + LLM</h1>
            
            <div class="main-content">
                <div class="history-section">
                    <div class="section-title">📚 历史对话</div>
                    <div class="history-box" id="historyBox">
                        <div class="history-item loading">
                            <span>加载历史对话中...</span>
                        </div>
                    </div>
                    <button onclick="refreshHistory()" class="refresh-btn">🔄 刷新</button>
                </div>
                
                <div class="chat-section">
                    <div class="section-title">💬 对话界面</div>
                    <div class="chat-box" id="chatBox">
                        <div class="message ai">
                            系统就绪。请确保 MCP Server 已启动 (端口 8931)。<br>
                            您可以输入指令，例如：<b>"打开浏览器搜索一下当前北京的天气"</b>
                        </div>
                    </div>

                    <div class="loading" id="loadingTip">
                        ⚡ 正在调用 AgentService... (涉及 LLM 思考和 MCP 工具调用，请耐心等待 5-15秒)
                    </div>

                    <div class="input-group">
                        <input type="text" id="messageInput" placeholder="输入指令..." onkeypress="if(event.keyCode==13) sendMessage()">
                        <button onclick="sendMessage()" id="sendBtn">发送</button>
                    </div>
                </div>
                
                <div class="tools-section">
                    <div class="section-title">🔧 工具调用过程</div>
                    <div class="tools-box" id="toolsBox">
                        <div class="tool-log">
                            <span class="tool-step">等待工具调用...</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <script>
            let conversationId = null;
            let selectedHistoryId = null;

            // 页面加载时自动加载历史对话
            window.onload = function() {
                loadHistory();
            };

            function appendMessage(content, role) {
                const chatBox = document.getElementById('chatBox');
                const div = document.createElement('div');
                div.className = `message ${role}`;

                if (role === 'ai') {
                    // 解析 Markdown (支持图片显示)
                    div.innerHTML = marked.parse(content);
                } else {
                    div.textContent = content;
                }

                chatBox.appendChild(div);
                chatBox.scrollTop = chatBox.scrollHeight;
            }

            function appendToolLog(toolLog) {
                const toolsBox = document.getElementById('toolsBox');
                const div = document.createElement('div');
                div.className = `tool-log ${toolLog.status}`;
                
                let html = `
                    <div class="tool-step">步骤 ${toolLog.step}</div>
                    <div>
                        <span class="tool-name">${toolLog.tool_name}</span>
                        <span class="tool-status ${toolLog.status}">${toolLog.status}</span>
                    </div>
                `;
                
                if (toolLog.arguments && Object.keys(toolLog.arguments).length > 0) {
                    html += `<div class="tool-args">参数: ${JSON.stringify(toolLog.arguments)}</div>`;
                }
                
                if (toolLog.result) {
                    html += `<div class="tool-result">结果: ${toolLog.result}</div>`;
                }
                
                div.innerHTML = html;
                toolsBox.appendChild(div);
                toolsBox.scrollTop = toolsBox.scrollHeight;
            }

            function clearToolLogs() {
                const toolsBox = document.getElementById('toolsBox');
                toolsBox.innerHTML = '<div class="tool-log"><span class="tool-step">等待工具调用...</span></div>';
            }

            function clearChat() {
                const chatBox = document.getElementById('chatBox');
                chatBox.innerHTML = '<div class="message ai">
                    系统就绪。请确保 MCP Server 已启动 (端口 8931)。<br>
                    您可以输入指令，例如：<b>"打开浏览器搜索一下当前北京的天气"</b>
                </div>';
            }

            async function loadHistory() {
                const historyBox = document.getElementById('historyBox');
                historyBox.innerHTML = '<div class="history-item loading"><span>加载历史对话中...</span></div>';
                
                try {
                    // 调用调试专用的历史记录API
                    const response = await fetch('/api/debug/history/');
                    const res = await response.json();
                    
                    if (res && res.histories) {
                        const histories = res.histories;
                        
                        if (histories.length === 0) {
                            historyBox.innerHTML = '<div class="history-item"><span>暂无历史对话记录</span></div>';
                            return;
                        }
                        
                        // 渲染历史记录列表
                        historyBox.innerHTML = histories.map(history => `
                            <div class="history-item" onclick="selectHistory(${history.id}, '${history.title}', event)">
                                <span class="history-title">${history.title}</span>
                                <span class="history-desc">${history.description}</span>
                                <div class="history-meta">
                                    <span>${history.timestamp}</span>
                                    <span class="history-status ${history.status}">${history.status}</span>
                                </div>
                            </div>
                        `).join('');
                    } else {
                        historyBox.innerHTML = '<div class="history-item"><span>加载历史对话失败</span></div>';
                    }
                } catch (e) {
                    console.error('加载历史对话失败:', e);
                    historyBox.innerHTML = '<div class="history-item"><span>加载历史对话失败</span></div>';
                }
            }

            function refreshHistory() {
                loadHistory();
            }

            function selectHistory(historyId, title, event) {
                // 更新选中状态
                const historyItems = document.querySelectorAll('.history-item');
                historyItems.forEach(item => {
                    item.classList.remove('selected');
                });
                if (event && event.target) {
                    event.target.closest('.history-item').classList.add('selected');
                }
                
                // 更新当前选中的历史记录ID
                selectedHistoryId = historyId;
                conversationId = historyId;
                
                // 清空当前聊天和工具日志
                clearChat();
                clearToolLogs();
                
                // 可以在这里添加加载历史对话内容的逻辑
                appendMessage(`已选择历史对话: ${title}`, 'ai');
            }

            async function sendMessage() {
                const input = document.getElementById('messageInput');
                const msg = input.value.trim();
                if (!msg) return;

                const btn = document.getElementById('sendBtn');
                const loading = document.getElementById('loadingTip');

                // UI 更新
                appendMessage(msg, 'user');
                input.value = '';
                btn.disabled = true;
                loading.style.display = 'block';
                clearToolLogs();

                try {
                    const response = await fetch('/api/debug/chat', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({
                            message: msg,
                            conversation_id: conversationId
                        })
                    });

                    const res = await response.json();

                    if (res.code === 200) {
                        conversationId = res.data.conversation_id;
                        appendMessage(res.data.message, 'ai');
                        
                        // 显示工具调用过程
                        const toolLogs = res.data.tool_execution_logs || [];
                        if (toolLogs.length > 0) {
                            const toolsBox = document.getElementById('toolsBox');
                            toolsBox.innerHTML = '';
                            toolLogs.forEach(log => appendToolLog(log));
                        }
                        
                        // 刷新历史记录列表，确保最新的对话显示
                        loadHistory();
                    } else {
                        appendMessage(`❌ 错误: ${res.msg}`, 'ai');
                    }
                } catch (e) {
                    appendMessage(`❌ 请求异常: ${e.message}`, 'ai');
                } finally {
                    btn.disabled = false;
                    loading.style.display = 'none';
                }
            }
        </script>
    </body>
    </html>
    """
    return html_template


# ==================== 初始化与启动 ====================

def init_db():
    with app.app_context():
        # 使用 Alembic 执行数据库迁移，确保表结构与模型一致
        from flask_migrate import upgrade as migrate_upgrade
        
        print("🔧 开始执行数据库迁移...")
        try:
            # 执行所有未应用的迁移
            migrate_upgrade()
            print("✅ 数据库迁移完成")
        except Exception as e:
            print(f"⚠️  迁移执行过程中出现异常: {e}")
            print("🔧 尝试创建所有表...")
            # 如果迁移失败，尝试创建所有表（适用于全新数据库）
            db.create_all()
            print("✅ 表创建完成")
        
        # 创建测试用户
        if not User.query.filter_by(username='debug_user').first():
            user = User(username='debug_user', email='debug@example.com')
            user.password = '123456'
            db.session.add(user)
            db.session.commit()
            print("✅ 测试用户创建完成")
        else:
            print("✅ 测试用户已存在，跳过创建")
        
        print("✅ 测试数据库初始化完成")


if __name__ == '__main__':
    print("=" * 50)
    print("PyScreenBrain 架构验证服务启动")
    print(f"MCP Server 目标地址: {Config.MCP_SERVER_URL}")
    print("请访问: http://localhost:9999")
    print("=" * 50)

    init_db()
    # 开启 threaded=True 以支持并发请求，虽然 AgentService 内部会有锁
    app.run(debug=False, host='0.0.0.0', port=9999, threaded=True)
